package com.aiyige.page.advertisement.util;


import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.support.v4.app.FragmentActivity;
import android.text.TextUtils;
import android.util.Log;

import com.aiyige.MyApp;
import com.aiyige.R;
import com.aiyige.arouter.config.ARouterConfig;
import com.aiyige.base.db.DBHelper;
import com.aiyige.base.db.dao.AdFileDao;
import com.aiyige.base.db.dao.AdModelDao;
import com.aiyige.base.db.table.AdFile;
import com.aiyige.base.db.table.AdModel;
import com.aiyige.configs.MyConfig;
import com.aiyige.location.LocationUtil;
import com.aiyige.location.model.RegionData;
import com.aiyige.page.advertisement.model.AdDeploy;
import com.aiyige.page.advertisement.model.AdResponse;
import com.aiyige.page.advertisement.service.UpdateAdService;
import com.aiyige.utils.AppUtils;
import com.aiyige.utils.ListUtil;
import com.aiyige.utils.PreferenceUtil;
import com.aiyige.utils.UUIDUtil;
import com.alibaba.android.arouter.launcher.ARouter;
import com.alibaba.fastjson.JSON;
import com.j256.ormlite.misc.TransactionManager;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.stmt.UpdateBuilder;
import com.vondear.rxtools.RxFileTool;

import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;

import timber.log.Timber;

public class AdUtil {
    public static final int CONTROL_OPTION_DOWNLOAD = 1;
    public static final int CONTROL_OPTION_PAUSE = 2;
    public static final int CONTROL_OPTION_DELETE = 3;

    public static final long SCAN_INTERVAL_MS = 10000;
    public static final long DOWNLOAD_IDLE_TIMEOUT_MS = 5 * 60 * 1000;

    public static final int AD_FILE_TYPE_VIDEO = 1;
    public static final int AD_FILE_TYPE_IMAGE = 2;
    public static final int AD_FILE_TYPE_AUDIO = 3;
    public static final int AD_FILE_TYPE_WELCOME_VIDEO = 4;

    public static final int PROGRESS_STATUS_WAITING_DOWNLOAD = 5;
    public static final int PROGRESS_STATUS_DOWNLOADING = 6;
    public static final int PROGRESS_STATUS_DOWNLOAD_FINISHED = 7;
    public static final int PROGRESS_STATUS_DOWNLOAD_FAILED = 8;

    public static final String AD_STATUS_PROCESS = "process";
    public static final String AD_STATUS_WAITING = "waiting";
    public static final String AD_STATUS_EXPIRED = "expired";
    public static final String AD_STATUS_STOPPED = "stopped";
    public static final String AD_STATUS_CANCELLED = "cancelled";

    public static final String AD_POSITION_APP_OPEN = "app_open";
    public static final String AD_POSITION_DISCOVER_TOP = "discover_top";
    public static final String AD_POSITION_PC_MAINPAGE = "pc_mainpage";

    public static final int MAX_DOWNLOAD_THREAD = 10;


    public static final String ACTION_DOWNLOAD_UPDATE = "com.aiyige.ad.ACTION_DOWNLOAD_UPDATE";
    public static final String ACTION_DOWNLOAD_PROGRESS_STATUS_UPDATE = "com.aiyige.ad.ACTION_DOWNLOAD_PROGRESS_STATUS_UPDATE";


    public static final String AD_FILE_DIR = MyConfig.AIYIGE_ROOT_DIR + File.separator + "adFileDir" + File.separator;
    public static final String NOMEDIA = AD_FILE_DIR + ".nomedia";

    public static final String PREF_KEY_LAST_UPDATE_AD_TIMESTAMP = "com.aiyige.pref.ad.PREF_KEY_LAST_UPDATE_AD_TIMESTAMP";
    private static final String PREF_KEY_VERSION_NAME = "com.aiyige.pref.ad.PREF_KEY_VERSION_NAME";//ad模块专用，不要用在别处
    private static final String PREF_KEY_VERSION_NAME_FOR_WELCOME_VIDEO = "com.aiyige.pref.ad.PREF_KEY_VERSION_NAME_FOR_WELCOME_VIDEO";//welcomevideo专用，不要用在别处


    public static final long UPDATE_AD_INTERVAL_MS = 12 * 60 * 60 * 1000;
    public static final long RANDOM_DELAY_LOW_BOUND_MS = 30 * 1000;
    public static final long RANDOM_DELAY_RANGE_MS = 5 * 60 * 1000;

    public static void createStage() {
        RxFileTool.createOrExistsDir(AD_FILE_DIR);
        RxFileTool.createOrExistsFile(NOMEDIA);
    }

    public static void clearStage() {
        RxFileTool.deleteFilesInDir(AD_FILE_DIR);
        RxFileTool.createOrExistsFile(NOMEDIA);
    }

    public static void playAd(FragmentActivity activity, AdModel adModel) {
        if (adModel != null) {
            ARouter.getInstance()
                    .build(ARouterConfig.AdPage)
                    .withParcelable("adModel", adModel)
                    .navigation(activity);
        }
    }


    public static void maybeUpdateAd() {
        try {
            long adModelNum = AdModelDao.getDao().queryBuilder().countOf();
            if (adModelNum == 0 ||
                    !RxFileTool.isFileExists(AD_FILE_DIR) ||
                    ListUtil.isEmpty(RxFileTool.listFilesInDir(AD_FILE_DIR)) ||
                    RxFileTool.listFilesInDir(AD_FILE_DIR).size() <= 1 ||
                    checkAppNewInstallOrUpgrade()) {
                makeAdIsNeverUpdate();
            }
        } catch (Exception e) {
            makeAdIsNeverUpdate();
        }
        updateAdIfTooOld();
        installUpdateAdAlarm();
    }


    public static void makeAdIsNeverUpdate() {
        PreferenceUtil.putLong(PREF_KEY_LAST_UPDATE_AD_TIMESTAMP, 0);
    }

    public static boolean checkAppNewInstallOrUpgrade() {
        String prefVersionName = PreferenceUtil.getString(PREF_KEY_VERSION_NAME, "");
        String currentVersionName = AppUtils.getAppVersionName();
        if (TextUtils.isEmpty(currentVersionName) || !currentVersionName.equals(prefVersionName)) {
            PreferenceUtil.putString(PREF_KEY_VERSION_NAME, currentVersionName);
            return true;
        } else {
            return false;
        }
    }


    public static boolean checkAppNewInstallForWelcomeVideo() {
        String prefVersionName = PreferenceUtil.getString(PREF_KEY_VERSION_NAME_FOR_WELCOME_VIDEO, "");
        String currentVersionName = AppUtils.getAppVersionName();
        if (!TextUtils.isEmpty(currentVersionName) && TextUtils.isEmpty(prefVersionName)) {
            PreferenceUtil.putString(PREF_KEY_VERSION_NAME_FOR_WELCOME_VIDEO, currentVersionName);
            return false;//return true;
        } else {
            return false;
        }
    }

    public static void updateAdWithRandomDelay() {
        Random random = new Random();
        Handler handler = new Handler(Looper.getMainLooper());
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                UpdateAdService.startService(MyApp.getAppContext());
            }
        }, (long) (random.nextFloat() * RANDOM_DELAY_RANGE_MS) + RANDOM_DELAY_LOW_BOUND_MS);
    }

    public static void clearUselessAd() {
        try {
            List<AdModel> adModelList = AdModelDao.getDao().queryBuilder()
                    .where()
                    .ne(AdModel.CONTROL_OPTION, AdUtil.CONTROL_OPTION_DELETE)
                    .query();
            for (AdModel adModel : adModelList) {
                if (AdUtil.checkAdUseless(adModel)) {
                    try {
                        UpdateBuilder<AdFile, String> adFileUpdateBuilder = AdFileDao.getDao().updateBuilder();
                        adFileUpdateBuilder.updateColumnValue(AdFile.CONTROL_OPTION, AdUtil.CONTROL_OPTION_DELETE);
                        adFileUpdateBuilder.where().eq(AdFile.PARENT_ID, adModel.getId());
                        adFileUpdateBuilder.update();

                        UpdateBuilder<AdModel, String> adModelUpdateBuilder = AdModelDao.getDao().updateBuilder();
                        adModelUpdateBuilder.updateColumnValue(AdModel.CONTROL_OPTION, AdUtil.CONTROL_OPTION_DELETE);
                        adModelUpdateBuilder.where().eq(AdModel.ID, adModel.getId());
                        adModelUpdateBuilder.update();
                    } catch (Exception e) {
                        Timber.e("handleUselessAd:" + Log.getStackTraceString(e));
                    }
                }
            }
        } catch (Exception e) {
            Timber.e("handleUselessAd:" + Log.getStackTraceString(e));
        }
    }

    public static void downloadAd(AdResponse adResponse, String position, int fileType) throws Exception {
        AdModel adModel = AdModel.newBuilder()
                .id(UUIDUtil.generate())
                .adId(adResponse.getId())
                .createTime(adResponse.getCreateTime())
                .adStatus(AdUtil.convertRespAdStatusToAdModelAdStatus(adResponse.getStatus()))
                .adPosition(position)
                .controlOption(AdUtil.CONTROL_OPTION_DOWNLOAD)
                .progressStatus(AdUtil.PROGRESS_STATUS_WAITING_DOWNLOAD)
                .adDeployJson(JSON.toJSONString(AdUtil.convertPositionDetailListToAdDeployList(adResponse.getPositionDetail())))
                .updateTime(adResponse.getUpdateTime())
                .creator(adResponse.getCreator())
                .build();
        AdFile adFile = AdFile.newBuilder()
                .id(UUIDUtil.generate())
                .parentId(adModel.getId())
                .fileLocalUrl(AdUtil.AD_FILE_DIR + UUIDUtil.generate())
                .fileRemoteUrl(adResponse.getAppAdvertiseUrl())
                .fileType(fileType)
                .controlOption(AdUtil.CONTROL_OPTION_DOWNLOAD)
                .progressStatus(AdUtil.PROGRESS_STATUS_WAITING_DOWNLOAD)
                .linkMomentId(adResponse.getLinkMomentId())
                .router(adResponse.getLink())
                .linkMomentSummary(adResponse.getLinkMomentSummary())
                .createTime(adResponse.getCreateTime())
                .build();
        AdModelDao.getDao().create(adModel);
        AdFileDao.getDao().create(adFile);
    }

    public static void parse(final List<AdResponse> adResponseList) throws Exception {
        TransactionManager.callInTransaction(DBHelper.getInstance().getConnectionSource(), new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                if (ListUtil.isEmpty(adResponseList)) throw new Exception("ad is empty");
                UpdateBuilder<AdModel, String> updateBuilder = AdModelDao.getDao().updateBuilder();
                updateBuilder.updateColumnValue(AdModel.AD_STATUS, AdUtil.AD_STATUS_EXPIRED);
                updateBuilder.where().ne(AdModel.CONTROL_OPTION, AdUtil.CONTROL_OPTION_DELETE);
                updateBuilder.update();
                Iterator<AdResponse> adResponseIterator = adResponseList.iterator();
                while (adResponseIterator.hasNext()) {
                    AdResponse adResponse = adResponseIterator.next();
                    QueryBuilder<AdModel, String> queryBuilder = AdModelDao.getDao().queryBuilder();
                    List<AdModel> adModelList = queryBuilder.where()
                            .eq(AdModel.AD_ID, adResponse.getId())
                            .and()
                            .ne(AdModel.CONTROL_OPTION, AdUtil.CONTROL_OPTION_DELETE)
                            .query();
                    AdModel item = ListUtil.getFirstItem(adModelList);
                    if (item != null && item.getUpdateTime() == adResponse.getUpdateTime()) {
                        UpdateBuilder<AdModel, String> ubuilder = AdModelDao.getDao().updateBuilder();
                        ubuilder.updateColumnValue(AdModel.AD_STATUS, AdUtil.convertRespAdStatusToAdModelAdStatus(adResponse.getStatus()));
                        updateBuilder.where().eq(AdModel.ID, item.getId());
                        updateBuilder.update();
                        continue;
                    }

                    switch (adResponse.getPosition()) {
                        case AdResponse.AD_POSITION_APP_OPEN_IMAGE: {
                            downloadAd(adResponse, AdUtil.AD_POSITION_APP_OPEN, AdUtil.AD_FILE_TYPE_IMAGE);
                            break;
                        }
                        case AdResponse.AD_POSITION_APP_OPEN_VIDEO: {
                            downloadAd(adResponse, AdUtil.AD_POSITION_APP_OPEN, AdUtil.AD_FILE_TYPE_VIDEO);
                            break;
                        }
                        case AdResponse.AD_POSITION_DISCOVER_TOP: {

                            break;
                        }
                        case AdResponse.AD_POSITION_PC_MAINPAGE: {

                            break;
                        }
                    }
                }
                return null;
            }
        });
        clearUselessAd();
    }

    public static List<AdDeploy> convertPositionDetailListToAdDeployList(List<AdResponse.PositionDetail> positionDetailList) {
        List<AdDeploy> adDeployList = new LinkedList<>();
        try {
            for (AdResponse.PositionDetail positionDetail : positionDetailList) {
                adDeployList.add(AdDeploy.newBuilder()
                        .avocation(positionDetail.getAvocation())
                        .city(positionDetail.getCity())
                        .endTime(positionDetail.getEndTime())
                        .startTime(positionDetail.getStartTime())
                        .build());
            }
        } catch (Exception e) {

        }
        return adDeployList;
    }

    public static String convertRespAdStatusToAdModelAdStatus(String status) {
        if (TextUtils.isEmpty(status)) {
            return AdUtil.AD_STATUS_PROCESS;
        }
        switch (status) {
            case AdResponse.AD_STATUS_CANCELLED:
                return AdUtil.AD_STATUS_CANCELLED;
            case AdResponse.AD_STATUS_EXPIRED:
                return AdUtil.AD_STATUS_EXPIRED;
            case AdResponse.AD_STATUS_PROCESS:
                return AdUtil.AD_STATUS_PROCESS;
            case AdResponse.AD_STATUS_STOPPED:
                return AdUtil.AD_STATUS_STOPPED;
            case AdResponse.AD_STATUS_WAITING:
                return AdUtil.AD_STATUS_WAITING;
            default:
                return AdUtil.AD_STATUS_EXPIRED;
        }
    }

    public static boolean checkAdUseless(AdModel adModel) {
        try {
            List<AdDeploy> adDeployList = JSON.parseArray(adModel.getAdDeployJson(), AdDeploy.class);
            boolean useless = true;
            for (AdDeploy adDeploy : adDeployList) {
                if (adDeploy.getEndTime() >= System.currentTimeMillis() && (AdUtil.AD_STATUS_PROCESS.equals(adModel.getAdStatus()) || AdUtil.AD_STATUS_WAITING.equals(adModel.getAdStatus()))) {
                    useless = false;
                    break;
                }
            }
            return useless;
        } catch (Exception e) {
            return true;
        }
    }


    public static void installUpdateAdAlarm() {
        Intent intent = new Intent(MyApp.getAppContext(), UpdateAdService.class);
        PendingIntent pintent = PendingIntent.getService(MyApp.getAppContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        AlarmManager alarm = (AlarmManager) MyApp.getAppContext().getSystemService(Context.ALARM_SERVICE);
        if (alarm != null) {
            alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + UPDATE_AD_INTERVAL_MS, UPDATE_AD_INTERVAL_MS, pintent);
        }
    }

    public static void sendDownloadUpdateBroadcast() {
        MyApp.getAppContext().sendBroadcast(new Intent(ACTION_DOWNLOAD_UPDATE));
    }

    public static void sendDownloadProgressStatusUpdateBroadcast() {
        MyApp.getAppContext().sendBroadcast(new Intent(ACTION_DOWNLOAD_PROGRESS_STATUS_UPDATE));
    }


    public static void updateAdIfTooOld() {
        if (System.currentTimeMillis() - PreferenceUtil.getLong(PREF_KEY_LAST_UPDATE_AD_TIMESTAMP, 0) > UPDATE_AD_INTERVAL_MS) {
            PreferenceUtil.putLong(PREF_KEY_LAST_UPDATE_AD_TIMESTAMP, System.currentTimeMillis());
            Timber.e("updateCityIfTooOld:detect ad too old and will update immediately...");
            updateAdWithRandomDelay();
        }
    }


    public static AdModel getShouldPlayAd() {
//        if (checkAppNewInstallForWelcomeVideo()) {
//            return AdModel.newBuilder()
//                    .adFileList(Arrays.asList(AdFile.newBuilder()
//                            .fileType(AD_FILE_TYPE_WELCOME_VIDEO)
//                            .fileResId(R.raw.welcome_video)
//                            .build()))
//                    .build();
//        }
        QueryBuilder<AdModel, String> queryBuilder = AdModelDao.getDao().queryBuilder();
        List<AdModel> adModelList = new LinkedList<>();
        try {
            adModelList = queryBuilder.where()
                    .eq(AdModel.AD_STATUS, AdUtil.AD_STATUS_PROCESS)
                    .and()
                    .ne(AdModel.CONTROL_OPTION, AdUtil.CONTROL_OPTION_DELETE)
                    .and()
                    .eq(AdModel.PROGRESS_STATUS, AdUtil.PROGRESS_STATUS_DOWNLOAD_FINISHED)
                    .query();
        } catch (Exception e) {

        }
        if (ListUtil.isEmpty(adModelList)) return null;
        Iterator<AdModel> adModelIterator = adModelList.iterator();
        RegionData regionData = LocationUtil.getCurrentUserSelectRegion();
        String city = regionData == null ? "" : regionData.getCityName();
        List<String> userInterestNameList = new LinkedList<>();
        //TODO:populate userInterestNameList
        outLoop:
        while (adModelIterator.hasNext()) {
            AdModel adModel = adModelIterator.next();
            try {
                List<AdDeploy> adDeployList = JSON.parseArray(adModel.getAdDeployJson(), AdDeploy.class);
                if (ListUtil.isEmpty(adDeployList)) throw new Exception("ad deploy empty");
                boolean shouldPlay = false;
                for (AdDeploy adDeploy : adDeployList) {
                    if (adDeploy.getStartTime() > System.currentTimeMillis() || adDeploy.getEndTime() < System.currentTimeMillis())
                        continue;
//                    if (!TextUtils.isEmpty(city) && !city.equals(adDeploy.getCity()))
//                        continue;
//                    if (!userInterestNameList.isEmpty() && !userInterestNameList.contains(adDeploy.getAvocation()))
//                        continue;
                    shouldPlay = true;
                    break;
                }
                if (!shouldPlay) {
                    throw new Exception("should not play this ad");
                }
            } catch (Exception e) {
                adModelIterator.remove();
            }
        }
        Collections.sort(adModelList, new Comparator<AdModel>() {
            @Override
            public int compare(AdModel o1, AdModel o2) {
                if (o1.getLastPlayTimestamp() > o2.getLastPlayTimestamp()) {
                    return 1;
                } else if (o1.getLastPlayTimestamp() < o2.getLastPlayTimestamp()) {
                    return -1;
                } else {
                    return 0;
                }
            }
        });

        AdModel adModel = ListUtil.getFirstItem(adModelList);
        if (adModel != null) {
            try {
                UpdateBuilder<AdModel, String> adModelUpdateBuilder = AdModelDao.getDao().updateBuilder();
                adModelUpdateBuilder.updateColumnValue(AdModel.LAST_PLAY_TIMESTAMP, System.currentTimeMillis());
                adModelUpdateBuilder.where().eq(AdModel.ID, adModel.getId());
                adModelUpdateBuilder.update();
                QueryBuilder<AdFile, String> qBuilder = AdFileDao.getDao().queryBuilder();
                List<AdFile> adFileList = qBuilder.where()
                        .eq(AdFile.PARENT_ID, adModel.getId())
                        .and()
                        .ne(AdFile.CONTROL_OPTION, AdUtil.CONTROL_OPTION_DELETE)
                        .and()
                        .eq(AdFile.PROGRESS_STATUS, AdUtil.PROGRESS_STATUS_DOWNLOAD_FINISHED)
                        .query();
                if (ListUtil.isEmpty(adFileList)) {
                    throw new Exception("ad file empty");
                }
                adModel.setAdFileList(adFileList);
            } catch (Exception e) {
                adModel = null;
                try {
                    UpdateBuilder<AdModel, String> adModelUpdateBuilder = AdModelDao.getDao().updateBuilder();
                    adModelUpdateBuilder.updateColumnValue(AdModel.AD_STATUS, AdUtil.AD_STATUS_EXPIRED);
                    adModelUpdateBuilder.where().eq(AdModel.ID, adModel.getId());
                    adModelUpdateBuilder.update();
                } catch (Exception ex) {

                }
            }
        }
        return adModel;
    }
}
